package define

import (
	"errors"
	"time"
)

//***********ModBus标准协议**************
//---------03命令码 读多个寄存器-----------
//【主机发送帧】
//从站地址	功能码	起始（高）	起始（低）	数量（高）	数量（低）	校验（低位在前）
//06 		03 		00 			00 			00 			01 			85 BD
//【从机返回帧】
//从站地址	功能码	字节计数	字节1	字节2	校验
//06 		03 		02 		00 		06 		8D 86
//---------06命令码 写单个寄存器-----------
//【主机发送帧】
//从站地址	功能码	寄存器地址（高）	寄存器地址（低）	数据（高）	数据（低）	校验
//06 		06		00 				0F 				07 			E6 			3B C4
//【从机返回帧】
//从站地址	功能码	数据地址（高）	数据地址（低）	数据（高）	数据（低）	校验
//06 		06 		00 				0F 				07 			E6 			3B C4
//---------10命令码 写多个寄存器-----------
//【主机发送帧】
//从站地址	功能码	起始（高）	起始（低）	数量（高）	数量（低）	字节数N*2	第一个数据（高）	第一个数据（低） 。。。 第N个数据（高）	第N个数据（低）	校验
//06 		10 		00 			0F 			00 			06 			0B 			07 				E6 	000B001A0015002B 00 			32 				79 7F
//【从机返回帧】
//从站地址	功能码	起始（高）	起始（低）	数量（高）	数量（低）	校验
//06 		10 		00 			0F 			00 			06 			71 BF

//【从机错误返回】以上指令组包错误或有其他异常时 回返回错误码 01 02 03 04
//从站地址	主机发送功能码|0x80	错误码	校验
//06 		83 					03 		B0 F0
//****************************************

//ModBus寄存器操作指令码
const (
	FUNCTION_CODE_READ_ONE_OR_MORE = 0x03 //获取单个或多个连续寄存器上的数据
	FUNCTION_CODE_WRITE_ONE        = 0x06 //设置单个寄存器上的数据
	FUNCTION_CODE_WRITE_MORE       = 0x10 //设置多个连续寄存器上的数据
)

//错误返回指令码
const (
	ERROR_COMMON = 0x80
	ERROR_CUSTOM = 0x14
)

// commands
const (
	/*
		原则上门禁服务不做锁485地址的读写操作，原因为：
			1. 如果是单独通信，那么指令是一定要带上正确的地址的，也就是说地址应该是预先知晓的，已经预先知晓了，就没有必要单独做读写了。
			2. 如果是广播通信，那么设备是不会做回复的，就不存在读取一说，至于设置，在一个串口多接设备的情况下，广播设置地址也没意义。
		所以，一主多从时，需要脱离主机前提下使用其他串口工具改锁地址，使其唯一
	*/
	ACTION_SET_ADDR             = 0x01 // 设置地址（编号）
	ACTION_GET_ADDR             = 0x02 // 读取地址
	ACTION_GET_RECORD           = 0x03 // 获取刷卡记录
	ACTION_SET_TIME             = 0x04 // 设置门禁时间
	ACTION_GET_TIME             = 0x05 // 获取门禁时间
	ACTION_SET_FP_PUT_STEP      = 0x06 // 设置指纹录取进度
	ACTION_GET_FP_PUT_STEP      = 0x07 // 获取指纹录取进度
	ACTION_SET_UNLOCK_WAIT_TIME = 0x08 // 设置等待开锁时间（1-99秒）
	ACTION_GET_UNLOCK_WAIT_TIME = 0x09 // 获取等待开锁时间（1-99秒）
	ACTION_UNLOCK               = 0x0A // 远程开锁
	ACTION_LOCK                 = 0x0B // 远程闭锁
	ACTION_SET_TOKEN            = 0x0C // 门禁权限下发
	ACTION_GET_TOKEN            = 0x0D // 获取门禁权限
	ACTION_GET_TOKEN_COUNT      = 0x0E // 获取密码、卡片、指纹数量
	ACTION_FP_READ_WRITE        = 0x0F // 指纹模板的读写控制
	ACTION_GET_ONE_FP           = 0x10 // 指纹单包读取
	ACTION_SET_ONE_FP           = 0x11 // 指纹单包写入
)

//权限的增删改查
const (
	OPT_TYPE_ADD      = 1
	OPT_TYPE_MODIFY   = 2
	OPT_TYPE_DELETE   = 3
	OPT_TYPE_CLEAR    = 4
	OPT_TYPE_ENTRY_FP = 5 //仅读取指纹
)

//指纹模板的读写控制
const (
	FP_READ_START  = 1
	FP_READ_END    = 2
	FP_WRITE_START = 3
	FP_WRITE_END   = 4
)

//指纹进度
const (
	FP_STEP_CLEAR  = 0 //默认 每次开始录指纹时会清零
	FP_STEP_FIRST  = 1 //第一步完成
	FP_STEP_SECOND = 2 //第二步完成
	FP_STEP_OK     = 3 //录指纹完成
	FP_STEP_FAIL   = 4 //录指纹失败
)

//记录
const (
	EVENT_NORMAL_NO_MORE     = iota //记录已经取完
	EVENT_NORMAL_CONTINUE           //记录已经取完
	EVENT_WARN_IDX_NOT_MATCH        //记录收发包的序列号不一致
	EVENT_ERROR_OCCUR               //记录收发包错误
)

//权限类型
const (
	TOKEN_TYPE_PASSWORD     = 1
	TOKEN_TYPE_CARD         = 2
	TOKEN_TYPE_FINGER_PRINT = 3
)

//查询锁状态
type GetStatus struct {
	Status int //锁状态  0 - 锁柄关闭 1 - 锁柄开启
}

//记录信息
type RecordInfo struct {
	Addr          int       //锁485地址
	CardNo        string    //用户卡号
	Password      string    //用户密码，在协议里面要拆分为前三位和后三位
	FingerprintNo string    //用户指纹编号
	TokenStatus   int       //权限状态（有效/受限/无效）1：有效卡/密码/指纹；2：受限卡/密码/指纹；3：无效卡/密码/指纹
	RecordType    int       //记录类型（无/密码/卡/指纹）0:无动作 1:密码动作 2:刷卡动作 3:指纹动作 (20s后自动归0)
	RecordTime    time.Time //发生时间
	LockStatus    int       //手柄状态 0：手柄闭合，1：手柄断开
}

//时间
type TimeInfo struct {
	SystemTime time.Time
}

//解锁延时时间
type UnlockWaitTimeInfo struct {
	WaitTime int //等待开锁时间(1-99s)
}

//权限信息
type TokenInfo struct {
	TokenType     int       //权限类型（1 密码  2 刷卡  3 指纹）
	TokenStatus   int       //权限状态（0 不启用 1 启用权限    默认为1启用）
	Deadline      time.Time //有效期，时间戳
	CardNo        string    //用户卡号 10进制卡号
	Password      string    //用户密码 十进制密码转成高低各两字节的十六进制数据 长度必须为6,注意前3位不能全为0
	FingerprintNo string    //槽位，用户指纹编号
}

//权限类型统计计数
type TokenCount struct {
	PasswordCnt    int //密码数量(0-100)
	CardCnt        int //卡片数量(0-100)
	FingerprintCnt int //指纹数量(0-99)
}

//指纹录取进度
type FingerprintPutStepInfo struct {
	Step int
}

//单包指纹数据
type OneFingerprintPacket struct {
	PackerNum int       //包序号 0-27
	Data      [130]byte //单包指纹数据130字节
}

//指纹模板的读写控制
type FingerprintReadWriteInfo struct {
	Step int //1 读开始 2 读结束 3 写开始 4 写结束
}

//开锁方式 十位表示开锁类型，个位表示开锁方式
var eventTypeMap = map[int]string{
	11: "密码开锁成功",
	12: "刷卡开锁成功",
	13: "指纹开锁成功",
	21: "密码开锁受限",
	22: "刷卡开锁受限",
	23: "指纹开锁受限",
	31: "密码开锁无效",
	32: "刷卡开锁无效",
	33: "指纹开锁无效",
}

//获取开锁事件内容
func GetEventContent(TokenStatus, RecordType int) string {
	eventStr := ""
	key := TokenStatus*10 + RecordType
	if _, ok := eventTypeMap[key]; ok {
		eventStr = eventTypeMap[key]
	}
	return eventStr
}

//远程指令
var (
	OPEN_LOCK    = "open_door"    //开锁
	FINGER_ENTRY = "finger_input" //指纹录入
)

//门锁指令通信结果
const (
	SEND_COMMAND_RESULT_SUCCESS = iota
	SEND_COMMAND_RESULT_FAIL
)

//门锁接收命令错误信息
var (
	ERROR_COMMAND_FAIL           = errors.New("command failed")
	ERROR_SLOT_OVERFLOW          = errors.New("slot overflow")
	ERROR_CARD_SLOT_OVERFLOW     = errors.New("card slot overflow")
	ERROR_PASSWORD_SLOT_OVERFLOW = errors.New("password slot overflow")
	ERROR_FINGER_SLOT_OVERFLOW   = errors.New("finger slot overflow")
	ERROR_Card_Full              = errors.New("add card overflow")
	ERROR_UnKnown                = errors.New("unknown error")
	ERROR_RESPONSE_NOTPTR        = errors.New("response input is not ptr")
)

//去除后2位校验码的最小回包长度
var RecvAtLeastLen = 5 //除去0x80及0x14的错误回复

//token停用启用
const (
	TOKEN_FLAG_DISABLE = 0
	TOKEN_FLAG_ENABLE  = 1
)

//当前链表存储表名
const (
	DRIVER_CURRENT_STORE_TOKEN    = "driver_current_store_token"
	DRIVER_CURRENT_STORE_INTERVAL = "driver_current_store_interval"
	DRIVER_CURRENT_STORE_HOLIDAY  = "driver_current_store_holiday"
)
